local name, gotGestures = ...

local genericbackdrop = {	
			bgFile = "Interface/ChatFrame/ChatFrameBackground", 
			edgeFile = "Interface/Tooltips/UI-Tooltip-Border", 
			tile = true, tileSize = 16, edgeSize = 16, 
			insets = { left = 3, right = 3, top = 5, bottom = 3 }
		}

-- Util functions
local function GetTableLength(t)
	local count = 0
	for _ in next, t do
		count = count + 1
	end
	return count
end

local tmptable
local function GetTableValueByNumber(t, index)
	if not tmptable or #tmptable ~= GetTableLength(t) then
		tmptable = {}
		for k,v in pairs(t) do
			tmptable[#tmptable+1] = k
		end
		table.sort(tmptable)
	end
	return tmptable[index], t[tmptable[index]]
end

gotGestures:Listen("UpdatePath", function(self, event, path)
	local frame = _G[StaticPopup_Visible("gotGesturesBindingPopup")]
	if frame then
		frame.editBox:SetText(path)
	end
end)

local function CreateFrameTitle(frame, title)
	frame.title = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
	frame.title:SetPoint("TOPLEFT", 0, 12)
	frame.title:SetText(title)
end

-- Create script editor frame.
local scriptEditor = CreateFrame("Frame")
scriptEditor.name = "Script Editor"
scriptEditor.parent = "gotGestures"

local title = scriptEditor:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
title:SetText("Script Editor")
title:SetJustifyH("LEFT")
title:SetJustifyV("TOP")
title:SetPoint("TOPLEFT", 16, -16)

local editBackdrop = CreateFrame("Frame", nil, scriptEditor)
editBackdrop:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -20)
editBackdrop:SetWidth(381)
editBackdrop:SetHeight(350)
editBackdrop:SetBackdrop(genericbackdrop)
editBackdrop:SetBackdropColor(0.1,0.1,0.1,0.5)
editBackdrop:SetBackdropBorderColor(0.4,0.4,0.4)

local scriptName = CreateFrame("EditBox", "gg_scriptNameEditBox", scriptEditor, "InputBoxTemplate")
scriptName:SetFontObject("GameFontNormalSmall")
scriptName:SetTextColor(1,1,1)
scriptName:SetWidth(200)
scriptName:SetHeight(12)
scriptName:SetPoint("TOPLEFT", editBackdrop, 16, -20)
scriptName:SetAutoFocus(false)
CreateFrameTitle(scriptName, "Script Name")
scriptEditor.scriptName = scriptName

local functionName = CreateFrame("EditBox", "gg_FunctionNameEditBox", scriptEditor, "InputBoxTemplate")
functionName:SetFontObject("GameFontNormalSmall")
functionName:SetTextColor(1,1,1)
functionName:SetWidth(200)
functionName:SetHeight(12)
functionName:SetPoint("TOPLEFT", scriptName, 0, -30)
functionName:SetAutoFocus(false)	
CreateFrameTitle(functionName, "Function Name")
scriptEditor.functionName = functionName

local functionArgs = CreateFrame("EditBox", "gg_functionArgumentsEditBox", scriptEditor, "InputBoxTemplate")
functionArgs:SetFontObject("GameFontNormalSmall")
functionArgs:SetTextColor(1,1,1)
functionArgs:SetWidth(200)
functionArgs:SetHeight(12)
functionArgs:SetPoint("TOPLEFT", functionName, 0, -30)
functionArgs:SetAutoFocus(false)
CreateFrameTitle(functionArgs, "Function arguments")
scriptEditor.functionArgs = functionArgs

local codeBackground = CreateFrame("Frame", nil, editBackdrop)
codeBackground:SetBackdrop(genericbackdrop)
codeBackground:SetBackdropColor(0,0,0, 0.5)
codeBackground:SetPoint("TOPLEFT", functionArgs, "BOTTOMLEFT", -5, -20)
codeBackground:SetPoint("BOTTOMRIGHT", editBackdrop, -16, 16)
CreateFrameTitle(codeBackground, "Script code")

local codeScrollFrame = CreateFrame("ScrollFrame", "gotGestures_codeEditScrollFrame", codeBackground, "UIPanelScrollFrameTemplate")
codeScrollFrame:SetPoint("TOPLEFT", codeBackground, "TOPLEFT", 5, -5)
codeScrollFrame:SetPoint("BOTTOMRIGHT", codeBackground, "BOTTOMRIGHT", -27, 5)
codeScrollFrame:SetWidth(320)
codeScrollFrame:SetHeight(65)

local code = CreateFrame("EditBox", "gotGestures_codeEditBox", editBackdrop)
code:SetFontObject("GameFontNormalSmall")
code:SetTextColor(1,1,1)
code:SetWidth(320)
code:SetHeight(70)
code:SetAutoFocus(false)
code:SetMultiLine()

codeScrollFrame:SetScrollChild(code)
codeScrollFrame:EnableMouse()
codeScrollFrame:SetScript("OnMouseUp", function()
	code:SetFocus()
end)

scriptEditor.code = code

code:SetScript("OnEnterPressed", function(self)
	self:Insert("\n")
end)
code:SetScript("OnTabPressed", function(self)
	self:Insert("    ")
end)
code:SetScript("OnEscapePressed", code.ClearFocus)

local OnEnter = function(self)
	self.text:SetTextColor(1,1,1)
end

local OnLeave = function(self)
	self.text:SetTextColor(1,1,0)
end

local savebtn = CreateFrame("Button", nil, editBackdrop)
savebtn:EnableMouse()
savebtn:SetPoint("BOTTOMLEFT", 0, 5)
savebtn:SetSize(50, 12)
savebtn.text = savebtn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
savebtn.text:SetAllPoints()
savebtn.text:SetText("save")

savebtn:SetScript("OnEnter", OnEnter)
savebtn:SetScript("OnLeave", OnLeave)
savebtn:SetScript("OnClick", function(self)
	local body = code:GetText()
	local success
	
	if body:len() > 0 then
		success = gotGestures:AddCode(scriptName:GetText(), body)
	else
		success = gotGestures:AddFunction(scriptName:GetText(), functionName:GetText(), functionArgs:GetText())
	end
	
	if success then
		scriptEditor.menu:refresh()
		InterfaceOptionsFrame_OpenToCategory("gotGestures")
	end
end)

local deletebtn = CreateFrame("Button", nil, editBackdrop)
deletebtn:EnableMouse()
deletebtn:SetPoint("BOTTOM", 0, 5)
deletebtn:SetSize(50, 12)
deletebtn.text = deletebtn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
deletebtn.text:SetAllPoints()
deletebtn.text:SetText("delete")

deletebtn:SetScript("OnEnter", OnEnter)
deletebtn:SetScript("OnLeave", OnLeave)
deletebtn:SetScript("OnClick", function(self)
	gotGestures:DeleteScript(scriptName:GetText())
	scriptEditor:Clear()
	scriptEditor.menu:refresh()
	InterfaceOptionsFrame_OpenToCategory("gotGestures")
end)

local clearbtn = CreateFrame("Button", nil, editBackdrop)
clearbtn:EnableMouse()
clearbtn:SetPoint("BOTTOMRIGHT", 0, 5)
clearbtn:SetSize(50, 12)
clearbtn.text = clearbtn:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
clearbtn.text:SetAllPoints()
clearbtn.text:SetText("clear")

clearbtn:SetScript("OnEnter", OnEnter)
clearbtn:SetScript("OnLeave", OnLeave)
clearbtn:SetScript("OnClick", function(self)
	scriptEditor:Clear()
end)

function scriptEditor:Clear()
	self.scriptName:SetText("")
	self.functionName:SetText("")
	self.functionArgs:SetText("")
	self.code:SetText("")
end

function scriptEditor:SelectScript(name)
	if not name then
		return print("No script name was passed to SelectScript.")
	end
	
	-- Clear any existing data.
	scriptEditor:Clear()
	
	local data = gotGestures.db.scripts[name]
	
	self.scriptName:SetText(name)
	
	if data.code then
		self.code:SetText(data.code)
	else
		self.functionName:SetText(data.func)
		self.functionArgs:SetText(data.args)
	end
end

local menu

menu = CreateFrame("Frame")
menu.name = "gotGestures"
menu.refresh = function(self) self.gestureList:update() end
InterfaceOptions_AddCategory(menu)
InterfaceOptions_AddCategory(scriptEditor)

scriptEditor.menu = menu

--Titletext.
local title = menu:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
title:SetText("gotGestures")
title:SetJustifyH("LEFT")
title:SetJustifyV("TOP")
title:SetPoint("TOPLEFT", 16, -16)

local subTitle = menu:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
subTitle:SetWordWrap(true)
subTitle:SetJustifyH("LEFT")
subTitle:SetJustifyV("TOP")
subTitle:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -8)
subTitle:SetPoint("RIGHT", -32, 0)
subTitle:SetHeight(32)
subTitle:SetText("Left-click to change bindings.\nShift + Right-click to remove bindings.\nRight-click to edit a script or remove it.")

local btnHeight, numButtons = 16, 20
local width = InterfaceOptionsFramePanelContainer:GetWidth()-30

local gestureList = CreateFrame("ScrollFrame", "gotGesturesScrollFrame", menu, "FauxScrollFrameTemplate")
gestureList:SetPoint("TOPLEFT", subTitle, "BOTTOMLEFT", 0, -8)
gestureList:SetPoint("BOTTOMRIGHT", -30, 16)

StaticPopupDialogs["gotGesturesBindingPopup"] = {
	text = "Set gesture for |cffffff00\"%s\"|r.\nPlease hold down the gotGestures button and draw your gesture, or enter one in the editbox below.",
	hasEditBox = 1,
	button1 = ACCEPT,
	button2 = CANCEL,
	timeout = 0,
	-- Editbox has annoying auto-focus. Kill it.
	OnShow = function(self) self.editBox:SetAutoFocus(false) self.editBox:ClearFocus() end,
	OnHide = function(self) self.editBox:SetAutoFocus(true) end,
	EditBoxOnEscapePressed = function(self) self:ClearFocus() end,
	
	OnAccept = function(self)
		local gesture = self.editBox:GetText():trim()
		if gesture == "" then
			return true
		end
		
		gesture = gesture:upper()
		
		if gotGestures.binds[gesture] and gotGestures.binds[gesture] ~= self.data then
			print(gotGestures.binds[gesture].." has been unbound.")
		end
		
		-- Remove old gesture.
		local oldGesture = gotGestures:GetBindingForScript(gotGestures.binds, self.data)
		if oldGesture then
			gotGestures.binds[oldGesture] = nil
		end

		-- Set new gesture
		gotGestures.binds[gesture] = self.data

		gestureList:update()
	end
	
}

local function OnEnter(self)
	self.scriptname:SetTextColor(1,1,0)
	self.gesture:SetTextColor(1,1,0)
end

local function OnLeave(self)
	self.scriptname:SetTextColor(1,1,1)
	self.gesture:SetTextColor(1,1,1)
end

local function OnClick(self, button)
	if button == "LeftButton" then
		local script = self.scriptname:GetText()
		StaticPopup_Show("gotGesturesBindingPopup", script, nil, script)
	else
		if IsShiftKeyDown() then 
			local gesture = self.gesture:GetText()
			if gesture and gesture ~= "" then
				gotGestures.binds[gesture] = nil
				gestureList:update()
			end
		else
			scriptEditor:SelectScript(self.scriptname:GetText())
			InterfaceOptionsFrame_OpenToCategory(scriptEditor)
		end
	end
end

--Create the ScrollFrame entry frames.
previous = nil
for i=1, numButtons do
	--Button
	frame = CreateFrame("Button",nil,menu)
	frame:SetPoint("TOPLEFT", previous or subTitle, "BOTTOMLEFT", 0, previous and 0 or -8)
	frame:SetHeight(btnHeight)
	frame:SetWidth(width)
	frame:RegisterForClicks("LeftButtonUp", "RightButtonUp")
	frame:SetScript("OnEnter", OnEnter)
	frame:SetScript("OnLeave", OnLeave)
	frame:SetScript("OnClick", OnClick)
	
	--Button text.
	frame.scriptname = frame:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
	frame.scriptname:SetPoint("LEFT")
	frame.scriptname:SetJustifyH("LEFT")
	
	frame.gesture = frame:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
	frame.gesture:SetPoint("TOPRIGHT")
	frame.gesture:SetPoint("BOTTOMRIGHT")
	frame.gesture:SetJustifyH("RIGHT")
	
	gestureList["button"..i] = frame
	
	previous = frame
end

function gestureList:update()
	local offset = FauxScrollFrame_GetOffset(self)
	local name, link
	local length = GetTableLength(gotGestures.db.scripts)
	FauxScrollFrame_Update(self, length, numButtons, btnHeight)
	for line=1, numButtons do
		if line+offset <= length then
			name = GetTableValueByNumber(gotGestures.db.scripts, (line+offset))
			self["button"..line].scriptname:SetText(name)
			self["button"..line].gesture:SetText(gotGestures:GetBindingForScript(gotGestures.binds, name))
			self["button"..line]:Show()
		else
			self["button"..line]:Hide()
		end
	end
end

gestureList:SetScript("OnShow", function(self) self:update() end)
gestureList:SetScript("OnHide", function(self) StaticPopup_Hide("gotGesturesBindingPopup") end)
gestureList:SetScript("OnVerticalScroll", function(self, offset) 
	FauxScrollFrame_OnVerticalScroll(self, offset, btnHeight, self.update)
end)
menu.gestureList = gestureList

SlashCmdList["gotGestures"] = function() InterfaceOptionsFrame_OpenToCategory(menu) end
SLASH_gotGestures1 = "/gotgestures"
SLASH_gotGestures2 = "/gg"